package com.ruoyi.process.dynamic.service.impl;


import cn.hutool.core.collection.CollUtil;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.common.core.page.PageUtil;
import com.ruoyi.common.utils.BeanUtils;
import com.ruoyi.process.dynamic.service.BpmnDynamicService;
import com.ruoyi.process.pipemaintainence.domain.BpmnApproval;
import com.ruoyi.process.pipemaintainence.provider.BpmnBusinessProvider;
import com.ruoyi.process.pipemaintainence.service.BpmnApprovalService;
import com.ruoyi.process.pipemaintainence.service.IDrainagePipeMainService;
import com.ruoyi.system.domain.SysUser;
import com.ruoyi.system.service.ISysUserService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zengqingfa
 * @date 2019/12/4 11:24
 * @description
 * @email zengqingfa_java@163.com
 */
@Service
public class BpmnDynamicServiceImpl implements BpmnDynamicService {

    @Autowired
    protected RepositoryService repositoryService;

    @Autowired
    protected TaskService taskService;

    @Autowired
    protected HistoryService historyService;
    @Autowired
    protected RuntimeService runtimeService;

    protected static Map<String, ProcessDefinition> PROCESS_DEFINITION_CACHE = new HashMap<String, ProcessDefinition>();

    @Autowired
    protected IDrainagePipeMainService drainagePipeMainService;
    @Autowired
    protected ISysUserService userService;
    @Autowired
    protected BpmnApprovalService bpmnApprovalService;
    @Autowired
    protected BpmnBusinessProvider bpmnBusinessProvider;

    @Override
    public Page<Map<String, Object>> processDefinitionList(Integer pageNo, Integer pageSize) {
        List<Map<String, Object>> listMap = new ArrayList<>();
        Page<Map<String, Object>> page = new Page<>(pageSize);
        int[] pageParams = PageUtil.init(pageNo, pageSize);
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().orderByDeploymentId().desc();
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage(pageParams[0], pageParams[1]);
        if (CollUtil.isNotEmpty(processDefinitionList)) {
            for (ProcessDefinition processDefinition : processDefinitionList) {
                Map<String, Object> values = new HashMap<>();
                values.put("id", processDefinition.getId());
                values.put("name", processDefinition.getName());
                values.put("key", processDefinition.getKey());
                values.put("version", processDefinition.getVersion());
                values.put("diagramResourceName", processDefinition.getDiagramResourceName());
                values.put("category", processDefinition.getCategory());
                values.put("description", processDefinition.getDescription());
                values.put("resourceName", processDefinition.getResourceName());
                listMap.add(values);
            }
        }
        page.setTotalCount(processDefinitionQuery.count());
        page.setResult(listMap);
        return page;
    }

    @Override
    public Page<Map<String, Object>> IgnoreTodoAndClaimTaskList(Integer pageNo, Integer pageSize, String userId) {
        List<Map<String, Object>> listMap = new ArrayList<>();
        Page<Map<String, Object>> page = new Page<>(pageSize);
        int[] pageParams = PageUtil.init(pageNo, pageSize);
        //获取获选人待办任务列表，需要判断是候选人的任务签收还是直接办理
        TaskQuery taskQuery = taskService.createTaskQuery();
        List<Task> tasks = taskQuery.taskCandidateOrAssigned(userId).active().orderByTaskCreateTime().asc().listPage(pageParams[0], pageParams[1]);
        if (CollUtil.isNotEmpty(tasks)) {
            for (Task task : tasks) {
                Map<String, Object> values = new HashMap<>();
                values.put("id", task.getId());
                values.put("name", task.getName());
                values.put("category", task.getCategory());
                values.put("assignee", task.getAssignee());
                values.put("description", task.getDescription());
                values.put("processDefinitionId", task.getProcessDefinitionId());
                values.put("owner", task.getOwner());
                values.put("formKey", task.getFormKey());
                values.put("taskDefinitionKey", task.getTaskDefinitionKey());
                listMap.add(values);
            }
        }
        page.setTotalCount(taskQuery.count());
        page.setResult(listMap);
        return page;
    }

    @Override
    public synchronized Page<Map<String, Object>> todoTaskList(Integer pageNo, Integer pageSize, String userId) {
        List<Map<String, Object>> listMap = new ArrayList<>();
        Page<Map<String, Object>> page = new Page<>(pageSize);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SysUser sysUser = userService.selectUserById(Long.valueOf(userId));
        //获取获选人待办任务列表
        TaskQuery taskQuery = taskService.createTaskQuery().taskCandidateOrAssigned(userId);
        // 待办任务   查询发起人
        List<Task> todoList = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().asc().active().list();
        if (CollUtil.isNotEmpty(todoList)) {
            for (Task task : todoList) {
                String processDefinitionId = task.getProcessDefinitionId();
                String processInstanceId = task.getProcessInstanceId();
                ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
                ProcessDefinition processDefinition = getProcessDefinition(processDefinitionId);
                Map<String, Object> singleTask = packageTaskInfo(sdf, task, processDefinition);
                singleTask.put("status", "todo");
                singleTask.put("sysUser", sysUser);
                singleTask.put("businessKey",processInstance.getBusinessKey());
                listMap.add(singleTask);
            }
        }
        // 等待签收的任务  查询发起人
        List<Task> toClaimList = taskService.createTaskQuery().taskCandidateUser(userId).orderByTaskCreateTime().asc().active().list();
        if (CollUtil.isNotEmpty(toClaimList)) {
            for (Task task : toClaimList) {
                String processDefinitionId = task.getProcessDefinitionId();
                String processInstanceId = task.getProcessInstanceId();
                ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
                ProcessDefinition processDefinition = getProcessDefinition(processDefinitionId);
                Map<String, Object> singleTask = packageTaskInfo(sdf, task, processDefinition);
                singleTask.put("status", "claim");
                singleTask.put("sysUser", sysUser);
                singleTask.put("businessKey",processInstance.getBusinessKey());
                listMap.add(singleTask);
            }
        }
        //listMap转换
        Long count = taskQuery.count();
        Integer totalCount = pageNo * pageSize;
        Integer countValue = count.intValue();
        if (BeanUtils.isNotEmpty(listMap)) {
            listMap = listMap.subList(pageSize * (pageNo - 1), (totalCount > countValue ? countValue : totalCount));
        }
        //转换完成之后查询任务的发起人
        for (Map<String, Object> map : listMap) {
            String taskId = (String) map.get("id");
            String startedBy = drainagePipeMainService.getStartedBy(taskId);
            SysUser user = userService.selectUserById(Long.valueOf(startedBy));
            map.put("startedByUserId", user.getUserId());
            map.put("startedByUserName", user.getUserName());
        }
        page.setTotalCount(count);
        page.setResult(listMap);
        return page;
    }



    private Map<String, Object> packageTaskInfo(SimpleDateFormat sdf, Task task, ProcessDefinition processDefinition) {
        Map<String, Object> singleTask = new HashMap<String, Object>();
        singleTask.put("id", task.getId());
        singleTask.put("name", task.getName());
        singleTask.put("createTime", sdf.format(task.getCreateTime()));
        singleTask.put("pdname", processDefinition.getName());
        singleTask.put("pdversion", processDefinition.getVersion());
        singleTask.put("pid", task.getProcessInstanceId());
        return singleTask;
    }


    private ProcessDefinition getProcessDefinition(String processDefinitionId) {
        ProcessDefinition processDefinition = PROCESS_DEFINITION_CACHE.get(processDefinitionId);
        if (processDefinition == null) {
            processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
            PROCESS_DEFINITION_CACHE.put(processDefinitionId, processDefinition);
        }
        return processDefinition;
    }

    @Override
    public Page<Map<String, Object>> running(Integer pageNo, Integer pageSize) {
        List<Map<String, Object>> listMap = new ArrayList<>();
        Page<Map<String, Object>> page = new Page<>(pageSize);
        int[] pageParams = PageUtil.init(pageNo, pageSize);
        ProcessInstanceQuery dynamicQuery = runtimeService.createProcessInstanceQuery().orderByProcessInstanceId().desc().active();
        List<ProcessInstance> list = dynamicQuery.listPage(pageParams[0], pageParams[1]);
        if (CollUtil.isNotEmpty(list)) {
            for (ProcessInstance processInstance : list) {
                Map<String, Object> values = new HashMap<String, Object>();
                values.put("id", processInstance.getId());
                values.put("name", processInstance.getName());
                values.put("businessKey", processInstance.getBusinessKey());
                values.put("deploymentId", processInstance.getDeploymentId());
                values.put("description", processInstance.getDescription());
                values.put("processDefinitionId", processInstance.getProcessDefinitionId());
                values.put("processDefinitionName", processInstance.getProcessDefinitionName());
                values.put("processDefinitionVersion", processInstance.getProcessDefinitionVersion());
                listMap.add(values);
            }
        }
        page.setTotalCount(dynamicQuery.count());
        page.setResult(listMap);
        return page;
    }

    @Override
    public Page<Map<String, Object>> finished(Integer pageNo, Integer pageSize) {
        List<Map<String, Object>> listMap = new ArrayList<>();
        Page<Map<String, Object>> page = new Page<>(pageSize);
        int[] pageParams = PageUtil.init(pageNo, pageSize);
        HistoricProcessInstanceQuery dynamicQuery = historyService.createHistoricProcessInstanceQuery().finished().orderByProcessInstanceEndTime().desc();
        List<HistoricProcessInstance> list = dynamicQuery.listPage(pageParams[0], pageParams[1]);
        if (CollUtil.isNotEmpty(list)) {
            for (HistoricProcessInstance historicProcessInstance : list) {
                Map<String, Object> values = new HashMap<String, Object>();
                values.put("id", historicProcessInstance.getId());
                values.put("name", historicProcessInstance.getName());
                values.put("businessKey", historicProcessInstance.getBusinessKey());
                values.put("deploymentId", historicProcessInstance.getDeploymentId());
                values.put("description", historicProcessInstance.getDescription());
                values.put("processDefinitionId", historicProcessInstance.getProcessDefinitionId());
                values.put("processDefinitionName", historicProcessInstance.getProcessDefinitionName());
                values.put("processDefinitionVersion", historicProcessInstance.getProcessDefinitionVersion());
                listMap.add(values);
            }
        }
        page.setTotalCount(dynamicQuery.count());
        page.setResult(listMap);
        return page;
    }

    @Override
    public Page<Map<String, Object>> finishedByAssignee(Integer pageNo, Integer pageSize, String userId) {
        List<Map<String, Object>> listMap = new ArrayList<>();
        Page<Map<String, Object>> page = new Page<>(pageSize);
        int[] pageParams = PageUtil.init(pageNo, pageSize);
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery();
        List<HistoricTaskInstance> taskList = historicTaskInstanceQuery.taskAssignee(userId).finished().orderByHistoricTaskInstanceEndTime().asc().listPage(pageParams[0], pageParams[1]);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SysUser sysUser = userService.selectUserById(Long.valueOf(userId));
        if (CollUtil.isNotEmpty(taskList)) {
            for (HistoricTaskInstance historicTaskInstance : taskList) {
                Map<String, Object> values = new HashMap<String, Object>();
                String taskId = historicTaskInstance.getId();
                values.put("sysUser", sysUser);//已办任务人
                values.put("taskId", taskId);
                values.put("name", historicTaskInstance.getName());
                values.put("durationInMillis", historicTaskInstance.getDurationInMillis());
                values.put("endTime", sdf.format(historicTaskInstance.getEndTime()));
                values.put("startTime", sdf.format(historicTaskInstance.getStartTime()));
                values.put("description", historicTaskInstance.getDescription());
                values.put("processDefinitionId", historicTaskInstance.getProcessDefinitionId());
                values.put("claimTime", historicTaskInstance.getClaimTime());
                values.put("getWorkTimeInMillis", historicTaskInstance.getWorkTimeInMillis());
                //状态 同意还是拒绝
                String processInstanceId = historicTaskInstance.getProcessInstanceId(); //实例id
                //  ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
                HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
                //业务主键
                values.put("businessKey", processInstance.getBusinessKey());
                String processDefinitionId = processInstance.getProcessDefinitionId();
                String name = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult().getName();
                //设置标题
                values.put("processDefinitionName", name);
                //查询流程是由谁发起的
                String startedBy = drainagePipeMainService.getStartedBy(taskId);
                SysUser user = userService.selectUserById(Long.valueOf(startedBy));
                values.put("startByUser", user);
                values.put("startedByUserId", user.getUserId());
                values.put("startedByUserName", user.getUserName());
                //设置流程的审批状态
                BpmnApproval approval = bpmnApprovalService.findByTaskId(taskId);
                values.put("opinion", approval.getOpinion()==true?"同意":"拒绝");
                listMap.add(values);
            }
        }
        page.setTotalCount(historicTaskInstanceQuery.count());
        page.setResult(listMap);
        return page;
    }


    @Override
    public Page<Map<String, Object>> findBpmnInstDetail(Integer pageNo, Integer pageSize) {
        List<Map<String, Object>> listMap = new ArrayList<>();
        Page<Map<String, Object>> page = new Page<>(pageSize);
        int[] pageParams = PageUtil.init(pageNo, pageSize);
        HistoricProcessInstanceQuery dynamicQuery = historyService.createHistoricProcessInstanceQuery().finished().orderByProcessInstanceEndTime().orderByProcessInstanceStartTime().desc();
        List<HistoricProcessInstance> list = dynamicQuery.listPage(pageParams[0], pageParams[1]);
        if (CollUtil.isNotEmpty(list)) {
            for (HistoricProcessInstance historicProcessInstance : list) {
                Map<String, Object> values = new HashMap<String, Object>();
                values.put("id", historicProcessInstance.getId());
                values.put("name", historicProcessInstance.getName());
                values.put("businessKey", historicProcessInstance.getBusinessKey());
                values.put("deploymentId", historicProcessInstance.getDeploymentId());
                values.put("description", historicProcessInstance.getDescription());
                values.put("processDefinitionId", historicProcessInstance.getProcessDefinitionId());
                values.put("processDefinitionName", historicProcessInstance.getProcessDefinitionName());
                values.put("processDefinitionVersion", historicProcessInstance.getProcessDefinitionVersion());
                listMap.add(values);
            }
        }
        page.setTotalCount(dynamicQuery.count());
        page.setResult(listMap);
        return page;
    }


    @Override
    public Page<Map<String, Object>> findBpmnInstByStartUserId(Integer pageNo, Integer pageSize, String userId) {
        List<Map<String, Object>> listMap = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Page<Map<String, Object>> page = new Page<>(pageSize);
        int[] pageParams = PageUtil.init(pageNo, pageSize);
        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery().orderByProcessInstanceEndTime().desc();
        List<HistoricProcessInstance> list = historicProcessInstanceQuery.startedBy(userId).listPage(pageParams[0], pageParams[1]);
        if (CollUtil.isNotEmpty(list)) {
            for (HistoricProcessInstance historicProcessInstance : list) {
                Map<String, Object> values = new HashMap<String, Object>();
                String processInstanceId = historicProcessInstance.getId();
                values.put("historicProcessInstance", historicProcessInstance);
                if (BeanUtils.isNotEmpty(historicProcessInstance.getEndTime())) {
                    //流程结束
                    values.put("endTime", sdf.format(historicProcessInstance.getEndTime()));
                    values.put("status", "end");
                } else {
                    //流程未结束
                    ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
                    values.put("status", "running");
                    values.put("activityId", processInstance.getActivityId());
                }
                //历史流程实例
                values.put("businessKey", historicProcessInstance.getBusinessKey());
                values.put("processDefinitionKey", historicProcessInstance.getProcessDefinitionKey());
                values.put("processDefinitionName", historicProcessInstance.getProcessDefinitionName());
                //流程开始时间
                values.put("startTime", sdf.format(historicProcessInstance.getStartTime()));
                //各个已审批流程的信息
                List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).list();
                List<HashMap<String, Object>> taskDetail = bpmnBusinessProvider.getTaskDetail(historicTaskInstanceList);
                values.put("taskDetail", taskDetail);
                values.put("durationInMillis", historicProcessInstance.getDurationInMillis());
                listMap.add(values);
            }
        }
        page.setTotalCount(historicProcessInstanceQuery.count());
        page.setResult(listMap);
        return page;
    }
}
